home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / tcp / Amster-source.lha / Amster_Install / Source / upload.c < prev    next >
C/C++ Source or Header  |  2001-03-14  |  13KB  |  509 lines

  1. /*
  2. ** Amster - Upload
  3. ** Copyright © 2000-2001 by Jacob Laursen
  4. **
  5. ** This program is free software; you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation; either version 2 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19.  
  20. #include "amster.h"
  21.  
  22. #include <proto/dos.h>
  23. #include <proto/exec.h>
  24.  
  25. #include "network.h"
  26.  
  27. #include <MUI/NListview_mcc.h>
  28. #include "amster_Cat.h"
  29.  
  30.  
  31. #define ULC_STATE 0
  32. #define ULC_SIZE 1
  33.  
  34. int ul_count = 0;
  35.  
  36. ULONG ul_new(struct IClass *cl, Object *obj, struct opSet *msg);
  37. void ul_cps(struct TransferData *data);
  38.  
  39.  
  40. MUI_DISPATCH(ul_dispatch)
  41. {
  42.     struct TransferData *data;
  43.  
  44.     switch(msg->MethodID) {
  45.         case OM_NEW:
  46.             return(ul_new(cl, obj, (APTR)msg));
  47.         case MUIM_Window_Setup:
  48.             return(dl_setup(cl, obj, (APTR)msg));
  49.         case MUIM_Window_Cleanup:
  50.             return(dl_muicleanup(cl, obj, (APTR)msg));
  51.         case UPLOAD_OPEN:
  52.             set(obj, MUIA_Window_Open, TRUE);
  53.             return NULL;
  54.         case UPLOAD_CLOSE:
  55.             set(obj, MUIA_Window_Open, FALSE);
  56.             return NULL;
  57.         case UPLOAD_UPDATE:
  58.             {
  59.             long pos = MUIV_NList_GetPos_Start;
  60.             data = INST_DATA(cl, obj);
  61.             DoMethod(data->list, MUIM_NList_GetPos, (((muimsg)msg)->arg1), &pos);
  62.             DoMethod(data->list, MUIM_NList_Redraw, pos);
  63.             return NULL;
  64.             }
  65.         case UPLOAD_CPS:
  66.             data = INST_DATA(cl, obj);
  67.             ul_cps(data);
  68.             return NULL;
  69.         case UPLOAD_ADD:
  70.             data = INST_DATA(cl, obj);
  71.             DoMethod(data->list, MUIM_NList_InsertSingle, (songtrans)(((muimsg)msg)->arg1), MUIV_NList_Insert_Bottom);
  72.             return NULL;
  73.         case UPLOAD_START:
  74.             data = INST_DATA(cl, obj);
  75.             ul_startq2(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3), (int)(((muimsg)msg)->arg4));
  76.             return NULL;
  77.         case UPLOAD_INFO:
  78.             data = INST_DATA(cl, obj);
  79.             TransferInfo(data);
  80.             return NULL;
  81.         case UPLOAD_ABORT:
  82.             data = INST_DATA(cl, obj);
  83.             TransferAbort(data);
  84.             return NULL;
  85.         case UPLOAD_CLEANUP:
  86.             data = INST_DATA(cl, obj);
  87.             TransferCleanup(data);
  88.             return NULL;
  89.         case UPLOAD_CLEANUP_SINGLE:
  90.             data = INST_DATA(cl, obj);
  91.             TransferCleanupSingle(data, (songtrans)(((muimsg)msg)->arg1));
  92.             return NULL;
  93.         case UPLOAD_WATCHER:
  94.             data = INST_DATA(cl, obj);
  95.             TransferWatcher(data);
  96.             return NULL;
  97.         case UPLOAD_COUNTDECREMENT:
  98.             data = INST_DATA(cl, obj);
  99.             if (--ul_count == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);
  100.             return NULL;
  101.         case UPLOAD_COUNTINCREMENT:
  102.             data = INST_DATA(cl, obj);
  103.             if (ul_count++ == 0) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);
  104.             return NULL;
  105.     }
  106.     return DoSuperMethodA(cl, obj, msg);
  107. }
  108.  
  109.  
  110. ULONG ul_new(struct IClass *cl, Object *obj, struct opSet *msg)
  111. {
  112.     static struct Hook uplistdispHook = { {0,0}, &translistdisp, NULL, NULL };
  113.     static struct Hook uplistdestHook = { {0,0}, &translistdest, NULL, NULL };
  114.     struct TransferData *data;
  115.     Object *list, *info, *BT_Abort, *BT_Clean;
  116.  
  117.     if (obj = (Object *)DoSuperNew(cl,obj,
  118.         MUIA_Window_Title, MSG_UPLOAD_TITLE,
  119.         MUIA_Window_ID, MAKE_ID('U','P','L','D'),
  120.         WindowContents, VGroup,
  121.             Child, list = NListviewObject,
  122.                 MUIA_NListview_NList, NListObject,
  123.                     InputListFrame,
  124.                     MUIA_Font, MUIV_Font_Tiny,
  125.                     MUIA_NList_Title, TRUE,
  126.                     MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
  127.                     MUIA_NList_DisplayHook, &uplistdispHook,
  128.                     MUIA_NList_DestructHook, &uplistdestHook,
  129.                     MUIA_CycleChain, 1,
  130.                 End,
  131.             End,
  132.             Child, info = TextObject,
  133.                 TextFrame,
  134.                 MUIA_Background, MUII_TextBack,
  135.                 MUIA_Text_PreParse, "\33c",
  136.             End,
  137.             Child, HGroup,
  138.                 Child, BT_Abort = SimpleButton(MSG_UPLOAD_ABORT_GAD),
  139.                 Child, BT_Clean = SimpleButton(MSG_UPLOAD_CLEANUP_GAD),
  140.             End,
  141.         End,
  142.         TAG_MORE, msg->ops_AttrList))
  143.     {
  144.         data = INST_DATA(cl,obj);
  145.         data->list = list;
  146.         data->info = info;
  147.  
  148.         data->ihnode.ihn_Object = obj;
  149.         data->ihnode.ihn_Millis = 1000;
  150.         data->ihnode.ihn_Method = UPLOAD_CPS;
  151.         data->ihnode.ihn_Flags  = MUIIHNF_TIMER;
  152.  
  153.         data->watchnode.ihn_Object = obj;
  154.         data->watchnode.ihn_Millis = 10000;
  155.         data->watchnode.ihn_Method = UPLOAD_WATCHER;
  156.         data->watchnode.ihn_Flags  = MUIIHNF_TIMER;
  157.  
  158.         DoMethod(BT_Abort, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, UPLOAD_ABORT  );
  159.         DoMethod(BT_Clean, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, UPLOAD_CLEANUP);
  160.         DoMethod(list, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, obj, 1, UPLOAD_INFO);
  161.         DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, obj, 1, UPLOAD_CLOSE);
  162.  
  163.         return((ULONG)obj);
  164.     }
  165.     return(0);
  166. }
  167.  
  168.  
  169. void ul_cps(struct TransferData *data)
  170. {
  171.     songtrans sd;
  172.     u_long item;
  173.     int i;
  174.  
  175.     for (i=0; ; i++) {
  176.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  177.         if (!item) return;
  178.         sd = (songtrans)item;
  179.         if (sd->state == DLS_UP) {
  180.             CalculateCps(sd);
  181.             DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  182.         }
  183.     }
  184. }
  185.  
  186.  
  187. void ul_addq(song s)
  188. /* This is the initial function, called from share.c */
  189. {
  190.     songtrans sd;
  191.     char *path;
  192.  
  193. #ifdef AMSTER_DEBUG
  194. gui_debugf("ul_addq() - upload count: %d, queue limit: %d", ul_count, prf->UploadQueueLimit);
  195. #endif
  196.  
  197.     path = MakeWinPath(s->title);
  198.     if (ul_count < prf->UploadQueueLimit) {
  199.         sprintf(nap_buf, "%s \"%s\"", s->user, path);
  200.         free(path);
  201.         nap_send(NAPC_UPLOADACCEPT);
  202.     }
  203.     else {
  204.         sprintf(nap_buf, "%s \"%s\" %d", s->user, path, prf->UploadQueueLimit);
  205.         free(path);
  206.         nap_send(NAPC_LOCALQUEUEFULL);
  207. #ifdef AMSTER_DEBUG
  208. gui_debugf("Queue limit reached! (%d)", prf->UploadQueueLimit);
  209. #endif
  210.         return;
  211.     }
  212.  
  213.     sd = malloc(sizeof(_songtrans));
  214.     if (!sd) return;
  215.     memset(sd, 0, sizeof(_songtrans));
  216.  
  217.     sd->song = nap_songdup(s);
  218.     if (!sd->song) {
  219.         free(sd);
  220.         return;
  221.     }
  222.  
  223.     sd->size = s->size;
  224.     sd->mynick = prf->user;
  225.     sd->type = TYPE_UPLOAD_OUT;
  226.     sd->reqtime = GetDateStamp();
  227.  
  228.     prf_event(PRFE_ULSTART, s->title);
  229.  
  230.     DoMethod(gui->uwin, UPLOAD_COUNTINCREMENT);
  231.  
  232. #ifdef AMSTER_DEBUG
  233. gui_debugf("upload count: %d", ul_count);
  234. #endif
  235.  
  236.     DoMethod(gui->uwin, UPLOAD_ADD, sd);
  237. }
  238.  
  239.  
  240. void ul_startq(char *title, char *user, u_long ip, int port, int link)
  241. /* This is the initial function, when the actual upload is about to
  242.    take place (acknowledged by server) - called from napster.c */
  243. {
  244.     DoMethod(gui->uwin, UPLOAD_START, title, user, ip, port);
  245. }
  246.  
  247.  
  248. void ul_startq2(struct TransferData *data, char *title, char *user, u_long ip, int port)
  249. /* ul_startq() continued (to get TransferData struct) */
  250. {
  251.     u_long tmp;
  252.     songtrans sd;
  253.     long i;
  254.     char *path;
  255.  
  256.     for (i=0; ; i++) {
  257.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  258.         if (!tmp) return;
  259.         sd = (songtrans)tmp;
  260.         path = MakeWinPath(sd->song->title);
  261.         if (sd->state==DLS_PREP && stricmp(user, sd->song->user)==0 && strcmp(title, path)==0) break;
  262.     }
  263.     free(path);
  264.  
  265.     if (sd->t) return;    /* Already in a thread */
  266.  
  267. #ifdef AMSTER_DEBUG
  268. gui_debugf("ul-ack [%s], port: %d, ip: %ld\n",title,port,ip);
  269. #endif
  270.  
  271.     /* We haven't filled out sd->song completely yet, since not much
  272.        information was available when the request was made */
  273.     sd->song->ip = ip;
  274.  
  275.     /* Why do we need the IP twice? Check and use only one of them! */
  276.     sd->ip = ip;
  277.     sd->port = port;
  278.  
  279.     sd->t = th_spawn(ul_handlemsg, "Amster uploader", &UploadThread, prf->UploadTaskPri, sd);
  280.     if (!sd->t) {
  281.         sd->state = DLS_ERROR;
  282.         DoMethod(gui->uwin, DL_UPDATE, sd);
  283.     }
  284. }
  285.  
  286.  
  287. void ul_handlemsg(thread t, int com, APTR data)
  288. {
  289.     songtrans sd=(songtrans)t->data;
  290.  
  291.     switch(com) {
  292.         case THC_STARTUP:
  293. #ifdef AMSTER_DEBUG
  294. gui_debugf("upload thread start");
  295. #endif
  296.             sd->ts = 1;
  297.             nap_sendbuf(NAPC_ULINC, "");
  298.             break;
  299.         case THC_EXIT:
  300. #ifdef AMSTER_DEBUG
  301. gui_debugf("upload thread exit = %ld", data);
  302. #endif
  303.             sd->error = (int)data;
  304.             if (sd->error == 0) DoMethod(gui->shwin, SHARE_UPDCOUNT, sd->song->title);
  305.             TransferHandleError(sd);
  306.             sd->ts = 0;
  307.             sd->t = NULL;
  308.             DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  309.             nap_sendbuf(NAPC_ULCOMPLETE, "");
  310.             if (sd->state == DLS_FIN && (prf->AutoCleanup == 2 || prf->AutoCleanup == 3)) {
  311.                 DoMethod(gui->uwin, UPLOAD_CLEANUP_SINGLE, sd);
  312.                 break;
  313.             }
  314.             break;
  315.         case DLC_STATE:
  316.             sd->state = (int)data;
  317.         case DLC_UPDATE:
  318.             DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  319.             break;
  320. #ifdef AMSTER_DEBUG
  321.         default:
  322.             gui_debugf("upload thread c: %d, d: %ld", com, data);
  323. #endif
  324.     }
  325. }
  326.  
  327.  
  328. /* Upload thread */
  329.  
  330. THREAD(UploadThread)
  331. {
  332.     thread t;
  333.     songtrans sd;
  334.     struct Library *DOSBase;
  335.     struct Library *SocketBase;
  336.     char *buffer, *path;
  337.     long tmp;
  338.     long s;
  339.     thmsg m;
  340.     int len;
  341.  
  342.     t = thr_init();
  343.     if (!t) return;
  344.     sd = t->data;
  345.  
  346.     if (!InitTransferThread(t, sd)) return;
  347.     s = sd->s;
  348.     buffer = sd->buffer;
  349.     DOSBase = sd->DOSBase;
  350.     SocketBase = sd->SocketBase;
  351.  
  352.     while (1) {
  353.         u_long sigs;
  354.  
  355.         sigs = Wait(sd->nsigm|sd->msigm);
  356.         if (sigs&(sd->msigm)) {
  357.             m = (thmsg)GetMsg(t->port);
  358.             if(m) {
  359.                 if (m->com == THC_EXIT) {
  360.                     thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  361.                     ExitTransferThread(sd, 0);
  362.                     return;
  363.                 }
  364.                 if (!m->isreply) {
  365.                     m->isreply=1;
  366.                     ReplyMsg((struct Message *)m);
  367.                 }
  368.             }
  369.         }
  370.  
  371.         if (sigs&(sd->nsigm)) {
  372.             FD_ZERO(&sd->fds);
  373.             FD_SET(s,&sd->fds);
  374.             sd->tv.tv_sec = 0;
  375.             sd->tv.tv_usec = 0;
  376.  
  377.             switch(sd->state) {
  378.                 case DLS_CON:
  379.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  380.                     {
  381.                         sd->state = DLS_INIT;
  382.                         tmp = 0;
  383.                         IoctlSocket(s, FIONBIO, (char*)&tmp);
  384.                         /* Disable non-blocking I/O to the socket */
  385.                     }
  386.  
  387.                 case DLS_INIT:
  388.                     if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
  389.                     {
  390.                         tmp = recv(s, buffer, 1, 0);
  391.                         if (tmp != 1) {
  392.                             sd->ErrorCode = Errno();
  393.                             ExitTransferThread(sd, ERROR_NET);
  394.                             return;
  395.                         }
  396.                         if (buffer[0] != '1') {
  397. #ifdef AMSTER_DEBUG
  398. gui_debugf("tmp: %ld, buffer[0]: %d", tmp, buffer[0]);
  399. #endif
  400.                             ExitTransferThread(sd, 30);
  401.                             return;
  402.                         }
  403.                         thr_message(t, DLC_UPDATE, 0);
  404.                         send(s, "SEND", 4, 0);
  405.  
  406.                         path = MakeWinPath(sd->song->title);
  407.                         sprintf(buffer, "%s \"%s\" %ld", sd->mynick, path, sd->song->size);
  408.                         free(path);
  409.                         send(s, buffer, strlen(buffer),0);
  410.  
  411.                         tmp = recv(s, buffer, 32, 0);
  412.                         if (tmp < 1) {
  413.                             sd->ErrorCode = Errno();
  414.                             ExitTransferThread(sd, ERROR_NET);
  415.                             return;
  416.                         }
  417.                         buffer[tmp] = '\0';
  418.  
  419.                         sd->cur = atoi(buffer);
  420.                         if (sd->cur == 0 && buffer[0] != '0') {
  421.                             if (strcmp(buffer, "FILE NOT REQUESTED") == 0) {
  422.                                 ExitTransferThread(sd, ERROR_NOTREQUESTED);
  423.                                 return;
  424.                             }
  425.                             else if (strcmp(buffer, "INVALID REQUEST") == 0) {
  426.                                 ExitTransferThread(sd, ERROR_INVALIDREQUEST);
  427.                                 return;
  428.                             }
  429. #ifdef AMSTER_DEBUG
  430. gui_debugf("error (please report this): %s\n", buffer);
  431. #endif
  432.                             ExitTransferThread(sd, 31);
  433.                             return;
  434.                         }
  435.  
  436.                         sd->f = Open(sd->song->title, MODE_OLDFILE);
  437.                         if (!sd->f) {
  438.                             sd->ErrorCode = IoErr();
  439.                             ExitTransferThread(sd, ERROR_FILEOPEN);
  440.                             return;
  441.                         }
  442.  
  443.                         Seek(sd->f, sd->cur, OFFSET_BEGINNING);
  444.                         sd->state = DLS_UP;
  445.                         sd->starttime = GetDateStamp();
  446.                         sd->resumestart = sd->cur;
  447.                         thr_message(t, DLC_UPDATE, 0);
  448.                     }
  449.  
  450.                 case DLS_UP:
  451.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  452.                     while (sd->cur < sd->size) {
  453.  
  454.                         len = Read(sd->f, buffer, 4096);
  455.                         if (len == -1) {    /* Error */
  456.                             sd->ErrorCode = IoErr();
  457.                             ExitTransferThread(sd, ERROR_FILEREAD);
  458.                             return;
  459.                         }
  460.                         if (len != 0) {
  461.                             tmp = send(s, buffer, len, 0);
  462.                             if (tmp == -1) {
  463.                                 sd->ErrorCode = Errno();
  464.                                 ExitTransferThread(sd, ERROR_NET);
  465.                                 return;
  466.                             }
  467.                             if (tmp != len) {
  468. #ifdef AMSTER_DEBUG
  469. gui_debugf("WARNING (please notify Laursen): all data from Read() was not send() - %ld/%ld.\n", len, tmp);
  470. #endif
  471.                             }
  472.                             sd->cur += len;
  473.                         }
  474.  
  475.                         if (len < 4096 && sd->cur < sd->size) {
  476.                             /* Read buffer wasn't filled and file is not finished */
  477.                             thr_message(t, DLC_STATE, (APTR)DLS_ERROR);
  478.                             ExitTransferThread(sd, 33);
  479.                             return;
  480.                         }
  481.  
  482.                         m = (thmsg)GetMsg(t->port);
  483.                         if (m) {
  484.                             if (m->com == THC_EXIT) {
  485.                                 thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  486.                                 ExitTransferThread(sd, 0);
  487.                                 return;
  488.                             }
  489.                             if (!m->isreply) {
  490.                                 m->isreply=1;
  491.                                 ReplyMsg((struct Message *)m);
  492.                             }
  493.                         }
  494.  
  495.                         FD_ZERO(&sd->fds);
  496.                         FD_SET(s,&sd->fds);
  497.                     }
  498.  
  499.                     thr_message(t, DLC_STATE, (APTR)DLS_FIN);
  500.                     ExitTransferThread(sd, 0);
  501.                     return;
  502.  
  503.             }
  504.         }
  505.     }
  506.  
  507.     ExitTransferThread(sd, 0);
  508. }
  509.